#!/usr/bin/env python
# encoding: utf-8
"""
@author:zwb
@file: articles.py
@contact: zwb15083976291@163.com
@time: 2021/12/11
"""
from datetime import datetime

from django.utils.decorators import method_decorator

from admin.serializers.articles import ArticleSerializer, CreateArticleSerializer, CreateDraftSerializer, \
    DraftSerializer, DeleteDraftSerializer, GetDraftSerializer, UpdateDraftSerializer, ArticlesPaginatorSerializer, \
    ArticleIdsListSerializer, UpdateArticleSerializer
from common.models import BlogDraft, BlogArticle, BlogTagArticle, BlogTag, BlogCategorie, BlogComments
from common.utils import add_article_search_cached_data
from utils.filters.views_filters import SearchDraftFilter, SearchArticlesFilter
from utils.responses import CommonResponse, CommonAPIResponseStatus
from utils.serializers.serializer import PaginatorSerializer
from utils.user_authentication import allow_admin_user
from utils.views import BasePaginateGenericAPIView
from django.db import transaction


@method_decorator(allow_admin_user, name='dispatch')
class ManagementArticleView(BasePaginateGenericAPIView):
    diff_methods_serializer_class = dict(post=CreateArticleSerializer, put=UpdateArticleSerializer,
                                         delete=ArticleSerializer, get=ArticleSerializer, patch=ArticleSerializer)
    diff_methods_request_params = dict(
        get=dict(required=['id']),
        post=dict(
            required=['articles_title', 'articles_content', 'articles_image_url', 'categorie', 'tags', 'articles_type',
                      'articles_status', 'articles_is_topping'], optional=['articles_reprint_url', 'draft_id']),
        put=dict(required=['id', 'articles_title', 'articles_content', 'articles_image_url', 'categorie', 'tags',
                           'articles_type', 'articles_status', 'articles_is_topping'],
                 optional=['articles_reprint_url']),
        delete=dict(required=['id']),
        patch=dict(required=['id', 'articles_is_topping'])
    )

    def get(self, request):
        ret, msg = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=msg)
        obj = BlogArticle.objects.filter(id=self.serializer.validated_data.get("id")).first()
        serial_fields = ['id', 'articles_title', 'articles_content', 'categorie', 'articles_image_url',
                         'articles_status', 'articles_type', 'articles_reprint_url', 'articles_is_topping']
        return CommonResponse(data=ArticleSerializer(obj, serial_fields=serial_fields).data)

    def post(self, request):
        ret, msg = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=msg)
        self.serializer.save()
        # 重新添加缓存
        add_article_search_cached_data()
        return CommonResponse(data=self.serializer.data)

    def put(self, request):
        ret, msg = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=msg)
        with transaction.atomic():
            article = BlogArticle.objects.filter(id=self.serializer.validated_data.get("id")).first()
            categorie = BlogCategorie.objects.filter(id=article.categorie).first()
            categorie.categorie_count -= 1
            categorie.save()
            # 更新时间
            self.serializer.validated_data["update_time"] = datetime.now()
            instance = self.serializer.select_field_update_obj().first()
            if self.serializer.validated_data.get("tags") is not None:
                self.update_article_tag(instance)
            categorie = BlogCategorie.objects.filter(id=instance.categorie).first()
            categorie.categorie_count += 1
            categorie.save()

        # 重新添加缓存
        add_article_search_cached_data()
        return CommonResponse()

    # 进行标签查询
    def update_article_tag(self, instance):
        tag_list = set(BlogTagArticle.objects.filter(article_id=instance.id).values_list('tag_id', flat=True))
        tags = set(self.serializer.validated_data.get("tags"))
        with transaction.atomic():
            # 需要删除的
            delete_ids = tag_list - tags
            BlogTagArticle.objects.filter(tag_id__in=delete_ids, article_id=instance.id).delete()
            for item in BlogTag.objects.filter(id__in=delete_ids).all():
                item.articles_count -= 1
                item.save()
            # 需要添加的标签
            add_tags = tags - tag_list
            add_article_tags = [BlogTagArticle(tag_id=item, article_id=instance.id) for item in add_tags]
            for item in BlogTag.objects.filter(id__in=add_tags).all():
                item.articles_count += 1
                item.save()

            BlogTagArticle.objects.bulk_create(add_article_tags)

    def delete(self, request):
        ret, msg = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=msg)
        self.delete_article()
        # 重新添加缓存
        add_article_search_cached_data()
        return CommonResponse()

    def patch(self, request):
        ret, msg = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=msg)
        self.serializer.select_field_update_obj()
        return CommonResponse()

    def delete_article(self):
        with transaction.atomic():
            instance = self.serializer.select_field_delete_obj()
            # 删除评论
            BlogComments.objects.filter(article_id=instance.id).delete()
            tag_articles = BlogTagArticle.objects.filter(article_id=instance.id).all()
            for item in tag_articles:
                tag_obj = BlogTag.objects.filter(id=item.tag_id).first()
                tag_obj.articles_count -= 1
                tag_obj.save()
                item.delete()
            categorie = BlogCategorie.objects.filter(id=instance.categorie).first()
            categorie.categorie_count -= 1
            categorie.save()


@method_decorator(allow_admin_user, name='dispatch')
class ManagementArticleListView(BasePaginateGenericAPIView):
    diff_methods_serializer_class = dict(delete=ArticleIdsListSerializer, get=ArticlesPaginatorSerializer)
    diff_methods_request_params = dict(
        get=dict(optional=['pageNum', 'pageSize', 'search', 'categorie', 'articles_type', 'articles_status'],
                 defualt_value=dict(pageNum=1, pageSize=5)),
        delete=dict(required=['ids']))

    filter_backends = [SearchArticlesFilter]

    def get(self, request):
        ret, message = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=message)
        query_set = self.filter_queryset(queryset=BlogArticle.objects.order_by('-articles_is_topping', '-create_time'))
        paginator, models = self.paginate_queryset(query_set, self.serializer.validated_data)
        return CommonResponse(data=self.get_paginated_response(self.serializer.validated_data, paginator,
                                                               ArticleSerializer(instance=models, many=True).data))

    def delete(self, request):
        ret, msg = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=msg)
        self.delete_article_list()
        # 重新添加缓存
        add_article_search_cached_data()
        return CommonResponse()

    def delete_article_list(self):
        ids = self.serializer.validated_data.get("ids")
        with transaction.atomic():
            articles_list = BlogArticle.objects.filter(id__in=ids).all()
            # 修改分类表中的计数
            for articles in articles_list:
                categorie = BlogCategorie.objects.filter(id=articles.categorie).first()
                categorie.categorie_count -= 1
                categorie.save()
                articles.delete()
                # 删除该文章的评论
                BlogComments.objects.filter(article_id__in=ids).delete()

            # 修改标签中的计数
            tag_articles_data = BlogTagArticle.objects.filter(article_id__in=ids).all()
            for item in tag_articles_data:
                tag = BlogTag.objects.filter(id=item.tag_id).first()
                if tag.articles_count > 0:
                    tag.articles_count -= 1
                tag.save()
                item.delete()


@method_decorator(allow_admin_user, name='dispatch')
class ManagementDraftView(BasePaginateGenericAPIView):
    diff_methods_serializer_class = dict(get=GetDraftSerializer, post=CreateDraftSerializer,
                                         put=UpdateDraftSerializer,
                                         delete=DeleteDraftSerializer)
    diff_methods_request_params = dict(get=dict(required=['id']),
                                       post=dict(required=['draft_title', 'draft_data']),
                                       put=dict(required=['id', 'draft_title', 'draft_data']),
                                       delete=dict(required=['id']))

    def get(self, request):
        ret, msg = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=msg)
        draft = BlogDraft.objects.filter(id=self.serializer.validated_data.get("id")).first()
        return CommonResponse(data=GetDraftSerializer(instance=draft).data)

    def post(self, request):
        ret, msg = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=msg)
        self.serializer.save()
        return CommonResponse(data=self.serializer.data)

    def put(self, request):
        ret, msg = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=msg)
        self.serializer.select_field_update_obj()
        return CommonResponse(data=self.serializer.data)

    def delete(self, request):
        ret, msg = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=msg)
        self.serializer.select_field_delete_obj()
        return CommonResponse()


@method_decorator(allow_admin_user, name='dispatch')
class ManagementDraftListView(BasePaginateGenericAPIView):
    serializer_class = PaginatorSerializer
    diff_methods_request_params = dict(
        get=dict(optional=['pageNum', 'pageSize', 'search'],
                 defualt_value=dict(pageNum=1, pageSize=4)))
    filter_backends = [SearchDraftFilter]

    def get(self, request):
        ret, message = self.validate_request_params()
        if not ret:
            return CommonResponse(CommonAPIResponseStatus.BAD_REQUEST, message=message)
        query_set = self.filter_queryset(queryset=BlogDraft.objects.order_by('-create_time'))
        paginator, models = self.paginate_queryset(query_set, self.serializer.validated_data)
        sear_data = dict(instance=models, many=True, serial_fields=["id", "draft_title", "create_time"])
        return CommonResponse(data=self.get_paginated_response(self.serializer.validated_data, paginator,
                                                               DraftSerializer(**sear_data).data))
